#include "UITextbox.h"
#include "../../Input/Mouse.h"
#pragma once

void __TextBox_OnFocusEnter(UIElement* sender)
{
	UITextbox* textbox = ToUITextbox(sender);
	textbox->Active = true;
}

void __TextBox_OnFocusLeave(UIElement* sender)
{
	UITextbox* textbox = ToUITextbox(sender);
	textbox->Active = false;
}

void __TextBox_HoverOn(UIElement* sender)
{
	Mouse::SetNewCursor(Mouse::Text);
}

void __TextBox_HoverOff(UIElement* sender)
{
	Mouse::SetNewCursor(Mouse::Default);
}

void __Textbox_OnKeyEvent(UIElement* sender, KeyEvt evt)
{
	UITextbox* textbox = ToUITextbox(sender);
	if (!textbox->Active || !(evt.event_type & MC_KEY_PRESSED)) return;

	TextChangedEvent text_change_evt = NoEvent; // no event

	// adding text
	if (evt.code < 37 || evt.code > 64 || evt.code == MC_SPACE || evt.code == MC_TAB || evt.code == MC_BACKTICK)
	{
		textbox->Text.insert(textbox->CursorPosition, 1, evt.key);
		textbox->CursorPosition++;
		text_change_evt = TextAdded;
	}

	// removing text
	if (evt.code == MC_BACKSPACE && textbox->Text.size() > 0 && textbox->CursorPosition > 0)
	{
		textbox->Text.erase(textbox->CursorPosition - 1, 1);
		textbox->CursorPosition--;
		text_change_evt = TextDeleted;
	}

	// processing arrow key cursor movements
	if (evt.code == MC_LEFT)
	{
		textbox->CursorPosition--;
		text_change_evt = CursorMovedLeft;
	}
	if (evt.code == MC_RIGHT)
	{
		textbox->CursorPosition++;
		text_change_evt = CursorMovedRight;
	}

	textbox->CursorPositionCorrection();
	textbox->VisibleIndicesCorrection(text_change_evt);
}

UITextbox::UITextbox()
{
	Width = 180;
	Height = 30;
	color = Color::White;

	SetDefaultOptions();
	SetupEventListeners();
	TextAllignment = TEXT_ALLIGNMENT_LEFT;
	CursorPosition = (int)Text.size();
}

UITextbox::UITextbox(float x, float y) : UIElement(x, y)
{
	Width = 180;
	Height = 30;
	color = Color::White;

	SetDefaultOptions();
	SetupEventListeners();
	TextAllignment = TEXT_ALLIGNMENT_LEFT;
	CursorPosition = (int)Text.size();
}

UITextbox::UITextbox(float x, float y, float width, float height) : UIElement(x, y, width, height)
{
	color = Color::White;

	SetDefaultOptions();
	SetupEventListeners();
	TextAllignment = TEXT_ALLIGNMENT_LEFT;
	CursorPosition = (int)Text.size();
}

UITextbox::UITextbox(float x, float y, float width, float height, std::string Text) : UIElement(x, y, width, height), IUITextElement(Text)
{
	color = Color::White;
	SetDefaultOptions();
	SetupEventListeners();
	TextAllignment = TEXT_ALLIGNMENT_LEFT;
	CursorPosition = (int)Text.size();
}

UITextbox::UITextbox(float x, float y, float width, float height, std::string Text, std::string FontName)
	: UIElement(x, y, width, height), IUITextElement(Text, FontName)
{
	color = Color::White;
	SetDefaultOptions();
	SetupEventListeners();
	TextAllignment = TEXT_ALLIGNMENT_LEFT;
	CursorPosition = (int)Text.size();
}

UITextbox::UITextbox(float x, float y, float width, float height, std::string Text, std::string FontName, int FontSize)
	: UIElement(x, y, width, height), IUITextElement(Text, FontName, FontSize)
{
	color = Color::White;
	SetDefaultOptions();
	SetupEventListeners();
	TextAllignment = TEXT_ALLIGNMENT_LEFT;
	CursorPosition = (int)Text.size();
}

UITextbox::UITextbox(float x, float y, float width, float height, std::string Text, std::string FontName, int FontSize, Color color)
	: UIElement(x, y, width, height, color), IUITextElement(Text, FontName, FontSize)
{
	SetDefaultOptions();
	SetupEventListeners();
	TextAllignment = TEXT_ALLIGNMENT_LEFT;
	CursorPosition = (int)Text.size();
}

UITextbox::UITextbox(float x, float y, float width, float height, std::string Text, std::string FontName, int FontSize, Color color, bool roundedCornersEnabled)
	: UIElement(x, y, width, height, color), IUITextElement(Text, FontName, FontSize)
{
	SetDefaultOptions();
	SetupEventListeners();
	TextAllignment = TEXT_ALLIGNMENT_LEFT;
	CursorPosition = (int)Text.size();
	this->RoundedCorners = roundedCornersEnabled;
}

UITextbox::UITextbox(float x, float y, float width, float height, std::string Text, std::string FontName, int FontSize, Color color, bool roundedCornersEnabled, float roundedCornerRadiusX, float roundedCornerRadiusY)
	: UIElement(x, y, width, height, color), IUITextElement(Text, FontName, FontSize)
{
	SetDefaultOptions();
	SetupEventListeners();
	TextAllignment = TEXT_ALLIGNMENT_LEFT;
	CursorPosition = (int)Text.size();
	this->RoundedCorners = roundedCornersEnabled;
	this->RoundCornerRadiusX = roundedCornerRadiusX;
	this->RoundCornerRadiusY = roundedCornerRadiusY;
}

void UITextbox::SetDefaultOptions()
{
	VisibleIndicesCorrection(NoEvent);
}

void UITextbox::SetupEventListeners()
{
	AddEnterFocusEvent(__TextBox_OnFocusEnter);			// when textbox is clicked and becomes active
	AddLeaveFocusEvent(__TextBox_OnFocusLeave);			// when textbox is no longer active
	AddMouseHoverOnEvent(__TextBox_HoverOn);				// changes cursor when mouse hovers over the textbox
	AddMouseHoverOffEvent(__TextBox_HoverOff);			// changes cursor when mouse hovers off the textbox
	AddKeyEvent(__Textbox_OnKeyEvent);					// processes key events inside the textbox
}

void __stdcall UITextbox::Draw(Graphics* graphics)
{
	// drawing the frame
	if (!this->RoundedCorners)
	{
		graphics->DrawRectangle(Position.x, Position.y, Width, Height, color.r, color.g, color.b, color.a, Stroke, true);
	}
	else
	{
		graphics->DrawRoundedRectangle(Position.x, Position.y, Width, Height, RoundCornerRadiusX, RoundCornerRadiusY,
			color.r, color.g, color.b, color.a, Stroke, true);
	}

	// drawing the text
	DWRITE_TEXT_ALIGNMENT textAllignment;
	DWRITE_PARAGRAPH_ALIGNMENT paragraphAllignment;
	MakeTextAllignment(this->TextAllignment, textAllignment, paragraphAllignment);

	if (_Max_Char_Count == 0)
	{
		_Max_Char_Count = (size_t)graphics->GetMaximumCharactersInLayout(FontName, FontSize, FontStyle, FontWeight, textAllignment, Width - MarginsLeft, Height);
		VisibleIndicesCorrection(NoEvent);
	}

	graphics->GetMetricsOfText(Text.substr(_visible_start_index, CursorPosition - _visible_start_index), FontName, FontSize, FontStyle, FontWeight,
		textAllignment, Width + 8000, Height - MarginsTop, &_Text_Width_In_Pixels, &_Text_Height_In_Pixels);

	CursorPositionCorrection();
	std::string VisibleText = CalculateVisibleText();

	// Updating text even when no key was placed (real-time text change detection)
	VisibleIndicesCorrection(TextAdded);
	VisibleIndicesCorrection(TextDeleted);
	
	graphics->drawText(VisibleText, FontName, FontSize, FontStyle, FontWeight, Position.x + MarginsLeft, Position.y + MarginsTop,
		Width + 8000, Height - MarginsTop, TextColor.r, TextColor.g, TextColor.b, TextColor.a, textAllignment, paragraphAllignment);

	// drawing cursor
	if (Active)
	{
		graphics->drawText(L"|", FontName, FontSize, FontStyle, FontWeight, 
			Position.x + MarginsLeft + _Text_Width_In_Pixels - (0.2f * FontSize), Position.y - MarginsTop, Width - MarginsLeft, Height - MarginsTop,
			TextColor.r, TextColor.g, TextColor.b, TextColor.a, textAllignment, paragraphAllignment);
	}
}

std::string UITextbox::CalculateVisibleText()
{
	return Text.substr(_visible_start_index, _visible_end_index - _visible_start_index);
}

void UITextbox::CursorPositionCorrection()
{
	if (CursorPosition < 0) CursorPosition = 0;
	if (CursorPosition > (int)Text.size()) CursorPosition = (int)Text.size();
}

void UITextbox::VisibleIndicesCorrection(TextChangedEvent evt)
{
	if (Text.size() < _Max_Char_Count)
	{
		_visible_start_index = 0;
		_visible_end_index = Text.size();
		return;
	}
	else if (evt != NoEvent)
	{
		switch (evt)
		{
		case TextAdded:
			_visible_start_index++;
			_visible_end_index++;
			break;
		case TextDeleted:
			if (_visible_start_index > 0)
			{
				_visible_start_index--;
				_visible_end_index--;
			}
			break;
		case CursorMovedLeft:
			if (CursorPosition <= (int)_visible_start_index)
			{
				if (_visible_start_index > 0)
				{
					_visible_start_index--;
					_visible_end_index--;
				}
			}
			break;
		case CursorMovedRight:
			if (_visible_end_index < Text.size() && CursorPosition >= (int)_visible_end_index)
			{
				_visible_start_index++;
				_visible_end_index++;
			}
			break;
		default:
			break;
		}
	}
}
